//
//  ViewController.swift
//  Books
//
//  Created by iMac on 2020/9/7.
//  Copyright © 2020 iMac. All rights reserved.
//

import UIKit
import WebKit

class ViewController: UIViewController {
    @IBOutlet weak var toolWidthConstraint: NSLayoutConstraint!
    @IBOutlet weak var webview: WKWebView!
    @IBOutlet weak var textView: UITextView!
    @IBOutlet weak var tool: UIView!
    @IBOutlet weak var toolContainer: UIView!
    @IBOutlet weak var tableView: UITableView!
    
    /// 当前的链接
    var curUrlStr = ""
    var readModeOn = false
    var requestLimit = true
    var lastRequestNextTime = 0
    var savedUrlList:Dictionary<String, String> = [:]
//    var lastMaxY = 0 {
//        didSet {
//            if lastMaxY - oldValue > 300 {
//                requestLimit = true
//            }
//        }
//    }
    let supportWebList = ["https://m.booktxt.net":
                            """
        document.getElementById("pb_next").click()
        """,
                          "https://m.biqudu.net":
                            """
        document.getElementById("pt_next").click()
        """,
                          "https://m.balingtxt.com":
                            """
        document.getElementById("pt_next").click()
        """,
                          "https://m.biquduu.com":
                            """
        document.getElementById("pt_next").click()
        """,
                          "https://youyouxs.com":
                            """
        document.getElementById("pt_next").click()
        """,
                          "https://m.biqudu.com":
                            """
        document.getElementById("pt_next").click()
        """,
    ]
    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // 初始化配置
        textView.delegate = self
        textView.scrollsToTop = false
        configWebview()
        // 加载上次的页面
        savedUrlList = (UserDefaults.standard.dictionary(forKey: "savedUrlList") as? Dictionary<String, String>) ?? [:]
        curUrlStr = UserDefaults.standard.string(forKey: "lastUrlStr") ?? ""
        if let url = URL(string: curUrlStr) {
            let request = URLRequest(url: url)
            webview.load(request)
        }
        // 监听进入后台
        NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: nil) { [weak self](_) in
            UserDefaults.standard.set(self?.curUrlStr, forKey: "lastUrlStr")
            UserDefaults.standard.set(self?.savedUrlList, forKey: "savedUrlList")
            UserDefaults.standard.synchronize()
        }
        
    }
    
    override func viewDidDisappear(_ animated: Bool) {
        super.viewDidDisappear(animated)
        
    }
    
    @IBAction func showTool(_ sender: UISwipeGestureRecognizer) {
        tool.backgroundColor = .systemGray5
        toolContainer.isHidden = false
        toolWidthConstraint.constant = 100
    }
    
    @IBAction func hideTool(_ sender: UIButton) {
        tool.backgroundColor = .clear
        toolContainer.isHidden = true
        toolWidthConstraint.constant = 28
    }
    
    @IBAction func showMarked(_ sender: UIButton) {
        tableView.reloadData()
        tableView.layer.borderColor = UIColor.link.cgColor
        tableView.layer.borderWidth = 3
        tableView.isHidden = !tableView.isHidden
    }
    
    @IBAction func saveUrl(_ sender: UIButton) {
        let alert = UIAlertController(title: "收藏当前网页", message: "请输入名称", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "取消", style: .cancel, handler: { (_) in
            
        }))
        alert.addAction(UIAlertAction(title: "收藏", style: .default, handler: {[weak self] (_) in
            let name = alert.textFields?[0].text
            if let url = self?.curUrlStr {
                self?.savedUrlList[url] = name
            }
        }))
        alert.addTextField { (textField) in
            
        }
        self.present(alert, animated: true, completion: nil)
    }
    
    
    @IBAction func readModeClick(_ sender: UIButton) {
        let readMode =  sender.isSelected
        if readMode {
            sender.isSelected = false
            // 退出阅读模式
            textView.isHidden = true
            webview.isHidden = false
            textView.text = ""
            textView.contentOffset = .zero
            readModeOn = false
        } else {
            sender.isSelected = true
            // 进入阅读模式
            textView.isHidden = false
            webview.isHidden = true
            readModeOn = true
            textView.text = ""
            configTextview()
        }
    }
    
    @IBAction func biquge_GO(_ sender: UIButton) {
        let urlstr = "https://www.feisxs.com"
        if let url = URL(string: urlstr) {
            let request = URLRequest(url: url)
            webview.load(request)
        }
    }
    
    @IBAction func booktxt_Go(_ sender: UIButton) {
        let urlstr = "https://m.booktxt.net"
        if let url = URL(string: urlstr) {
            let request = URLRequest(url: url)
            webview.load(request)
        }
    }
    
    @IBAction func txt80_Go(_ sender: UIButton) {
        let urlstr = "https://youyouxs.com"
        if let url = URL(string: urlstr) {
            let request = URLRequest(url: url)
            webview.load(request)
        }
    }
    
    @IBAction func wanben_Go(_ sender: UIButton) {
        let urlstr = "https://www.wbxs.org"
        if let url = URL(string: urlstr) {
            let request = URLRequest(url: url)
            webview.load(request)
        }
    }
    
    
    @IBAction func search_Go(_ sender: UIButton) {
        let alert = UIAlertController(title: "跳转", message: "请输入网址", preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "取消", style: .cancel, handler: { (_) in
            
        }))
        alert.addAction(UIAlertAction(title: "GO", style: .default, handler: {[weak self] (_) in
            let name = alert.textFields?[0].text
            if name != nil, let url = URL(string: name!) {
                let request = URLRequest(url: url)
                self?.webview.load(request)
            }
        }))
        alert.addTextField { (textField) in
            
        }
        self.present(alert, animated: true, completion: nil)
    }
    
    //MARK: - Private func -
    /// 配置过滤规则
    private func configWebview() {
        
        let blockStr = """
                [
                    {
                        "trigger":{
                            "url-filter":".*",
                            "if-domain":[
                                %@
                            ],
                            "load-type": ["third-party"]
                        },
                        "action":{
                            "type": "block"
                        }
                    }
                ]
                """
        
        let domainString = supportWebList.keys.map({"\""+($0.split(separator: "/").last ?? "")+"\""}) .joined(separator: ",")
        
        let jsonString = String(format: blockStr, domainString)
        
        // 取消去广告
        //        WKContentRuleListStore.default()?.compileContentRuleList(forIdentifier: "adv_block", encodedContentRuleList: jsonString, completionHandler: { (list, error) in
        //
        //            guard let contentRuleList = list else {
        //                print(error as Any)
        //                return
        //            }
        //            let configuration = self.webview.configuration
        //            configuration.userContentController.add(contentRuleList)
        //
        //        })
        
        self.webview.uiDelegate = self
        self.webview.navigationDelegate = self
        
    }
    
    private func configTextview() {
        print("\(#function)")
        
        let getHtml_js = "document.documentElement.innerHTML"
        webview.evaluateJavaScript(getHtml_js) { [weak self](html, error) in
            //            print(html)
            let text = self?.dealHtmlStr(html: (html as? String) ?? "")
            let yP = self?.textView.contentOffset
            self?.textView.text = (self?.textView.text ?? "") + text!
            self?.requestLimit = true
            if let yP = yP {
                self?.textView.setContentOffset(yP, animated: false)
                self?.textView.setNeedsDisplay()
            }
            print("textView text change ----- ")
        }
        
    }
    
    private func dealHtmlStr(html: String) -> String {
        // 逐一测试规则
        let regular1 = re.compile("<div\\sid=\"chaptercontent\"\\sclass=\"Readarea\\sReadAjax_content\"\\sstyle=\"font-size:\\s20px;\">(.*?)</div>", flags: .dotMatchesLineSeparators)
        if let matches = regular1.search(html) {
            var text = matches.group(1)!
            text = (text as NSString).replacingOccurrences(of: "<br>", with: "\n")
            text = (text as NSString).replacingOccurrences(of: "&nbsp;", with: " ")
            let re_p = re.compile("<p.*?</p>", flags: .dotMatchesLineSeparators)
            text = re_p.sub("\n\n\n", text)
            text = (text as NSString).trimmingCharacters(in: .whitespacesAndNewlines)
            text = "\n\n    " + text + "\n\n====================="
            
            return text
        }
        
        let regular2 = re.compile("<div\\sid=\"novelcontent\"\\sclass=\"novelcontent\">(.*?)</div>", flags: .dotMatchesLineSeparators)
        if let matches = regular2.search(html) {
            var text = matches.group(1)!
            text = (text as NSString).replacingOccurrences(of: "<br>", with: "\n")
            text = (text as NSString).replacingOccurrences(of: "&nbsp;", with: " ")
            let re_p = re.compile("<p>(.*?)</p>", flags: .dotMatchesLineSeparators)
            text = re_p.search(text)?.group(1) ?? ""
            text = (text as NSString).trimmingCharacters(in: .whitespacesAndNewlines)
            text = "\n\n    " + text + "\n\n====================="
            
            return text
        }
        
        let regular3 = re.compile("<div\\sid=\"nr1\">(.*?)</div>", flags: .dotMatchesLineSeparators)
        if let matches = regular3.search(html) {
            var text = matches.group(1)!
            text = (text as NSString).replacingOccurrences(of: "<br>", with: "\n")
            text = (text as NSString).replacingOccurrences(of: "&nbsp;", with: " ")
            text = (text as NSString).trimmingCharacters(in: .whitespacesAndNewlines)
            text = "\n\n    " + text + "\n\n====================="
            
            return text
        }
        
        let regular4 = re.compile("<div\\sid=\"chaptercontent\"\\sclass=\"Readarea\\sReadAjax_content\".*?>(.*?)</div>", flags: .dotMatchesLineSeparators)
        if let matches = regular4.search(html) {
            var text = matches.group(1)!
            text = (text as NSString).replacingOccurrences(of: "<br>", with: "\n")
            text = (text as NSString).replacingOccurrences(of: "&nbsp;", with: " ")
            let re_p = re.compile("<p\\sclass.*?>(.*?)</p>", flags: .dotMatchesLineSeparators)
            let list = re_p.finditer(text)
            let s = list.map { p -> String in
                if let p_str = p.group(1) {
                    return p_str
                }
                return ""
            }.joined()
            text = (s as NSString).trimmingCharacters(in: .whitespacesAndNewlines)
            text = "\n\n    " + text + "\n\n====================="
            
            return text
        }
        
        let regular5 = re.compile("<div\\sid=\"chaptercontent\".*?>(.*?)</div>", flags: .dotMatchesLineSeparators)
        if let matches = regular5.search(html) {
            var text = matches.group(1)!
            text = (text as NSString).replacingOccurrences(of: "<br>", with: "\n")
            text = (text as NSString).replacingOccurrences(of: "&nbsp;", with: " ")
            let re_p = re.compile("<p.*?>(.*?)</p>", flags: .dotMatchesLineSeparators)
            let list = re_p.finditer(text)
            let s = list.map { p -> String in
                if let p_str = p.group(1) {
                    return p_str
                }
                return ""
            }.joined()
            text = (s as NSString).trimmingCharacters(in: .whitespacesAndNewlines)
            text = "\n\n    " + text + "\n\n====================="
            
            return text
        }
        
        
        let regular6 = re.compile("<div\\sid=\"booktxt\".*?>(.*?)</div>", flags: .dotMatchesLineSeparators)
        if let matches = regular6.search(html) {
            
            let html1 = html.replacingOccurrences(of: "<div><script>try {t();} catch (err) {}</script></div>", with: "")
            let html2 = html1.replacingOccurrences(of: "<div><script>try {b();} catch (err) {}</script></div>", with: "")
            guard let matches2 = regular6.search(html2) else {
                return ""
            }
            var text = matches2.group(1)!
            text = (text as NSString).replacingOccurrences(of: "<br>", with: "\n")
            text = (text as NSString).replacingOccurrences(of: "&nbsp;", with: " ")
            let re_p = re.compile("<p.*?>(.*?)</p>", flags: .dotMatchesLineSeparators)
            let list = re_p.finditer(text)
            let s = list.map { p -> String in
                if let p_str = p.group(1) {
                    return p_str + "\n"
                }
                return ""
            }.joined()
            text = (s as NSString).trimmingCharacters(in: .whitespacesAndNewlines)
            text = "\n\n    " + text + "\n\n====================="
            
            return text
        }
        
        let regular7 = re.compile("<div\\sclass=\"yd_text2\".*?>(.*?)</div>", flags: .dotMatchesLineSeparators)
        if let matches = regular7.search(html) {
            var text = matches.group(1)!
            text = (text as NSString).replacingOccurrences(of: "<br>", with: "\n")
            text = (text as NSString).replacingOccurrences(of: "&nbsp;", with: " ")
            let re_p = re.compile("<p.*?>(.*?)</p>", flags: .dotMatchesLineSeparators)
            let list = re_p.finditer(text)
            let s = list.map { p -> String in
                if let p_str = p.group(1) {
                    return p_str + "\n"
                }
                return ""
            }.joined()
            text = (s as NSString).trimmingCharacters(in: .whitespacesAndNewlines)
            
            let title_re = re.compile("<div\\sclass=\"novel\".*?>.*?<h1>(.*?)</h1>", flags: .dotMatchesLineSeparators)
            var title = ""
            if let title_matches = title_re.search(html) {
                title = title_matches.group(1)!
            }
            
            text = "\n\n" + title + "\n\n" + text + "\n\n====================="
            
            return text
        }
        
        let regular8 = re.compile("<div\\sid=\"content\".*?>(.*?)</div>", flags: .dotMatchesLineSeparators)
        if let matches = regular8.search(html) {
            var text = matches.group(1)!
            text = (text as NSString).replacingOccurrences(of: "<br>", with: "\n")
            text = (text as NSString).replacingOccurrences(of: "&nbsp;", with: " ")
            let re_p = re.compile("<p.*?>(.*?)</p>", flags: .dotMatchesLineSeparators)
            let list = re_p.finditer(text)
            let s = list.map { p -> String in
                if let p_str = p.group(1) {
                    return p_str + "\n"
                }
                return ""
            }.joined()
            text = (s as NSString).trimmingCharacters(in: .whitespacesAndNewlines)
            
            let title_re = re.compile("<p\\sclass=\"chaptertitle\".*?>(.*?)</p>", flags: .dotMatchesLineSeparators)
            var title = ""
            if let title_matches = title_re.search(html) {
                title = title_matches.group(1)!
            }
            
            text = "\n\n" + title + "\n\n" + text + "\n\n====================="
            
            return text
        }
        
        return ""
    }
    
    private func requestNewview() {
        
        let currentT = Int(Date().timeIntervalSince1970)
        guard currentT - lastRequestNextTime > 5 else {
            return
        }
        lastRequestNextTime = currentT
        requestLimit = false
        
        let js = """
                    var a = document.getElementById("pb_next");
                    if (a == null) {
                        a = document.getElementById("pt_next");
                    }
                    if (a == null) {
                        a = document.getElementById("next_url");
                    }
                    if (a == null) {
                        a = document.getElementById("next");
                    }
                    if (a == null) {
                        a = document.getElementsByClassName("jump-chapter-links")[1];
                    }
                    if (a == null) {
                        if (document.getElementsByClassName("bottem1")[0]) {
                            a = document.getElementsByClassName("bottem1")[0].children[2];
                        }
                    }
                    if (a == null) {
                        if (document.getElementsByClassName("pereview")[0]) {
                            a = document.getElementsByClassName("pereview")[0].children[2];
                            if (a == null) {
                                a = document.getElementsByClassName("pereview")[0].children[1];
                            }
                        }
                    }
                    if (a != null) {
                        a.click();
                    }
            """
        
        webview.evaluateJavaScript(js, completionHandler: nil)
    }
    
    private func getNextView() {
        
        let yP = textView.contentOffset.y
        let maxY = textView.contentSize.height
        
        print("getNextView -- ",yP,maxY,requestLimit)
        
        if yP > 100 && maxY - yP < 1000 && requestLimit {
            requestNewview()
        }
    }
    
    
}

extension ViewController: WKNavigationDelegate, WKUIDelegate {
    //MARK: - WKNavigationDelegate
    
    func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        print("\(#function)")
        print("\(String(describing: navigationAction.request.url?.absoluteString))")
        
        decisionHandler(.allow)
    }
    
    func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
        print("error -- \(error)")
    }
    
    func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
        print("\(#function)")
        
        if readModeOn {
            configTextview()
        }
    }
    
    func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
        print("\(#function)")
        print("load url -- \(String(describing: webView.url))")
        
        curUrlStr = webView.url?.absoluteString ?? ""
    }
    
    //MARK: - WKUIDelegate
    func webView(_ webView: WKWebView, createWebViewWith configuration: WKWebViewConfiguration, for navigationAction: WKNavigationAction, windowFeatures: WKWindowFeatures) -> WKWebView? {
        print("\(#function)")
        if navigationAction.targetFrame == nil || !navigationAction.targetFrame!.isMainFrame {
            webView.load(navigationAction.request)
        }
        return nil
    }
}

extension ViewController: UIScrollViewDelegate, UITextViewDelegate {
    func scrollViewDidScroll(_ scrollView: UIScrollView) {
        print("\(#function)")
        getNextView()
    }
}


extension ViewController: UITableViewDataSource, UITableViewDelegate {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return savedUrlList.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        let names = [String](savedUrlList.values)
        cell.textLabel?.text = names[indexPath.row]
        cell.contentView.backgroundColor = .systemGray6
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let urls = [String](savedUrlList.keys)
        let urlStr = urls[indexPath.row]
        if let url = URL(string: urlStr) {
            let request = URLRequest(url: url)
            webview.load(request)
        }
        tableView.isHidden = true
    }
    
    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
    }
    
    func tableView(_ tableView: UITableView, editingStyleForRowAt indexPath: IndexPath) -> UITableViewCell.EditingStyle {
        return .delete
    }
    
    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            savedUrlList.remove(at: savedUrlList.index(savedUrlList.startIndex, offsetBy: indexPath.row))
        }
        tableView.reloadData()
    }
    
}
